package com.examples.gateway.helper.filter;

import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.examples.gateway.common.CheckState;
import com.examples.gateway.helper.Constants;
import com.examples.gateway.helper.config.GatewayHelperProperties;
import com.examples.gateway.helper.entity.UserDetail;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.http.HttpCookie;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * 获取当前的用户信息
 * @author Dai YaLu
 */
@Slf4j
public class GetUserDetailsFilter extends AbstractGlobalHelperFilter{

    private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();

    private final String protocol = "http://";

    @Autowired
    private WebClient.Builder builder;

    @Autowired
    private GatewayHelperProperties properties;
    @Override
    public Mono<Void> doFilter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = getToken(exchange.getRequest());
        if (StringUtils.isEmpty(token)) {
            return handleError(exchange, CheckState.PERMISSION_ACCESS_TOKEN_NULL);
        }
        // 检查Token是否被篡改
        if (properties.getTokenResolver().isEnableCheckTokenTamper()) {
            boolean pass = checkTokenTamper(exchange.getRequest(), token);
            if (!pass) {
                return handleError(exchange, CheckState.PERMISSION_ACCESS_TOKEN_INVALID);
            }
        }
        GatewayHelperProperties.TokenResolver resolver = properties.getTokenResolver();
//        String oauthUserApi = "http://airedge-oauth-service/token/checkToken";
        WebClient webClient = builder.baseUrl(protocol + resolver.getOAuthService()).build();
        return webClient
                .get()
                .uri(resolver.getGetUserDetailPath())
                .header(properties.getTokenResolver().getHeaderKey(), token)
                .exchangeToMono(resp -> {
                    if (!resp.statusCode().is2xxSuccessful()) {
                        return handleError(exchange, CheckState.PERMISSION_GET_USE_DETAIL_FAILED);
                    } else {
                        return resp.bodyToMono(UserDetail.class).flatMap(ed -> {
                            if (StringPool.ZERO.equals(ed.getCode())) {
                                exchange.getAttributes().put(Constants.EXAMPLES_GATEWAY_USER_DETAIL, ed.getData());
                                return chain.filter(exchange);
                            } else {
                                return handleError(exchange, CheckState.PERMISSION_GET_USE_DETAIL_FAILED);
                            }
                        });
                    }
                });
    }

    @Override
    public int getOrder() {
        return 40;
    }

    private boolean checkTokenTamper(final ServerHttpRequest req, String token){
        GatewayHelperProperties.TokenResolver resolver = properties.getTokenResolver();
        HttpCookie cookie = req.getCookies().getFirst(resolver.getValidateKey());
        if (null != cookie) {
            String ticket = cookie.getValue();
            if (StringUtils.isEmpty(ticket)) {
                return false;
            } else {
                return ENCODER.matches(token, ticket);
            }
        }
        return false;
    }

    /**
     * 解析请求中的Token，先重header中解析，再重cookie中解析，最后重请求参数中解析
     * @param req 请求信息
     * @return token
     */
    private String getToken(final ServerHttpRequest req) {
        GatewayHelperProperties.TokenResolver resolver = properties.getTokenResolver();
        String token = req.getHeaders().getFirst(resolver.getHeaderKey());
        if (StringUtils.isEmpty(token)) {
            HttpCookie cookie = req.getCookies().getFirst(resolver.getCookieKey());
            if (null != cookie) {
                token = cookie.getValue();
            }
            if (StringUtils.isEmpty(token)) {
                token = req.getQueryParams().getFirst(resolver.getQueryKey());
            }
        }
        if (StringUtils.isEmpty(token)) {
            return null;
        } else if (token.startsWith(resolver.getPrefix())) {
            token = token.substring(resolver.getPrefix().length());
        }
        return token;
    }

//    public static void main(String[] args) {
//        String passwd = "123456";
//        String p1 = ENCODER.encode("123456");
//        String p2 = ENCODER.encode("123456");
//        System.out.println(p1);
//        System.out.println(p2);
//        System.out.println(ENCODER.matches(passwd, p1));
//        System.out.println(ENCODER.matches(passwd, p2));
//    }

}
